home *** CD-ROM | disk | FTP | other *** search
- unit CachedCombo;
- {
- Author : Neil McClements
- Date : January '97
- C/right: (c) 1997 N. McClements
- Purpose: A TComboBox descendent which can be populated and
- the items/itemindex cached using file streams
- }
-
- interface
-
- uses
- Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
- StdCtrls, DBCtrls, DBTables, DB;
-
- //
- // TComboList - holds the items and itemindex briefly whilst written to/retrieved from
- // a stream
-
- type TComboList=class(TComponent)
- private
- FValues:TStringList;
- FItemIndex:longint;
- public
- constructor Create(AOwner:TComponent);override;
- destructor Destroy; override;
- published
- property ItemValues:TStringList read Fvalues write Fvalues;
- property SelectedItem:longint read FItemIndex write FItemIndex;
- end;
-
- //
- // TCachedCombo - allows the items to be filled from a datasource and cached
- //
-
- type
- TCachedCombo = class(TComboBox)
- private
- FConfigFile:string;
- FItemsFieldDataLink:TFieldDataLink;
- FUseCache:boolean;
- function GetItemsDataField:string;
- function GetItemsDataSource:TDataSource;
- procedure ItemsDataChange(Sender:TObject);
- procedure SetItemsDataField(const theFieldName:string);
- procedure SetItemsDataSource(theSource:TDataSource);
- protected
- procedure Notification(AComponent: TComponent; Operation: TOperation);
- procedure SetUseCache(CacheOnOff:boolean);
- public
- constructor Create(Owner:TComponent);override;
- destructor Destroy; override;
- function Populate:boolean;
- function ReadListFromStream:boolean;
- function WriteListToStream:boolean;
- published
- property ConfigFile:string read FConfigFile write FConfigFile;
- property ItemsDataField:string read GetItemsDataField write SetItemsDataField;
- property ItemsDataSource:TDataSource read GetItemsDataSource write SetItemsDataSource;
- property UseCache:boolean read FUseCache write SetUseCache default false;
- end;
-
- procedure Register;
-
- implementation
-
- procedure Register;
- begin
- RegisterComponents('more...', [TCachedCombo]);
- end;
-
- constructor TComboList.Create(AOwner:TComponent);
- begin
- inherited Create(AOwner);
-
- // Prepare memory to receive the items
- Fvalues:=TStringList.create;
- end;
-
- destructor TComboList.Destroy;
- begin
- // Tidy up after the component before calling its ancestor's destructor
- Fvalues.free;
- inherited destroy;
- end;
-
- constructor TCachedCombo.Create(Owner:TComponent);
- var
- exePath:string;
- begin
- inherited Create(Owner);
-
- // Prepare the data link
- FItemsFieldDataLink:=TFieldDataLink.Create;
- FItemsFieldDataLink.OnDataChange:=ItemsDataChange;
-
- // Default config file used to cache dates between application sessions
- if FConfigFile='' then
- begin
- exePath:=ExtractFilePath(application.exename);
- FConfigFile:=exePath+'Combo.cfg';
- end;
-
- // Register the date list component so Delphi knows how to handle it in file streams
- RegisterClass(TComboList);
- end;
-
- destructor TCachedCombo.Destroy;
- begin
- // Tidy up after the component before calling its ancestor's destructor
- FItemsFieldDataLink.free;
- inherited Destroy;
- end;
-
- function TCachedCombo.WriteListToStream:boolean;
- var
- stream:TfileStream;
- ComboList:TComboList;
- begin
- // Write the combo items to the cache via a file stream
- try
- ComboList:=TComboList.create(Owner);
- ComboList.ItemValues.assign(self.items);
- ComboList.SelectedItem:=ItemIndex;
- // check that if file not found for read then exception handled gracefully!
- stream:=TFileStream.create(FConfigFile, fmCreate or fmOpenWrite);
- stream.WriteComponent(ComboList);
- stream.free;
- ComboList.free;
- Result:=true;
- except
- on E:exception do
- Result:=false;
- end; // except
-
- end; // function
-
- function TCachedCombo.ReadListFromStream:boolean;
- var
- stream:TfileStream;
- ListComponent:TComponent;
- begin
- // Reload the combo items from the cache via a file stream
- try
- // check that if file not found for read then exception handled gracefully!
- stream:=TfileStream.create(FConfigFile, fmopenread);
- while not (stream.position = stream.size) do
- begin
- // Reda the next component in the stream and try and determine what is is
- ListComponent:=stream.ReadComponent(nil);
- if (ListComponent is TComboList) then
- begin
- items.assign((ListComponent as TComboList).ItemValues);
- self.ItemIndex:=(ListComponent as TComboList).SelectedItem;
- end;
- end;
- stream.free;
- Result:=true;
- except
- on E:EFOpenError do
- Result:=false;
- end; // except
- end;
-
- procedure TCachedCombo.SetUseCache(CacheOnOff:boolean);
- begin
- // Refresh the combo box whenever the developer switches the component mode from
- // cached to not-cached
-
- if (CacheOnOff=true) then
- ReadListFromStream
- else
- Populate;
- end;
-
- function TCachedCombo.Populate:boolean;
- var
- dSet:TDataset;
- begin
- // Fill the combo box items string list from the datasource - if the data link is still valid
- if (assigned(FItemsFieldDataLink) and (ItemsDataSource<>nil)) then
- begin
- self.clear;
- dSet:=FItemsFieldDataLink.DataSource.Dataset;
- dSet.Active:=true;
- dSet.first;
- while not dSet.eof do
- begin
- self.items.add(dSet.FieldByName(FItemsFieldDataLink.FieldName).AsString);
- dSet.next;
- end;
- // Record the updated details in the cache for next time...
- Result:=WriteListToStream;
- end
- else
- Result:=false;
- end;
-
- // The following functions maintain the datasource and data links references
-
- function TCachedCombo.GetItemsDataField:string;
- begin
- GetItemsDataField:=FItemsFieldDataLink.FieldName;
- end;
-
- function TCachedCombo.GetItemsDataSource:TDataSource;
- begin
- GetItemsDataSource:=FItemsFieldDataLink.DataSource;
- end;
-
- procedure TCachedCombo.SetItemsDataField(const theFieldName:string);
- begin
- FItemsFieldDataLink.FieldName:=theFieldName;
- end;
-
- procedure TCachedCombo.SetItemsDataSource(theSource: TDataSource);
- begin
- FItemsFieldDataLink.DataSource:=theSource;
- end;
-
- procedure TCachedCombo.ItemsDataChange(Sender:TObject);
- begin
- if FItemsFieldDataLink.Field = nil then
- FUseCache:=ReadListFromStream;
- end;
-
- procedure TCachedCombo.Notification(AComponent: TComponent; Operation: TOperation);
- begin
- // If the datasource is removed from the application, reset the data source reference
- inherited Notification(AComponent, Operation);
- if (Operation = opRemove) and (FItemsFieldDataLink <> nil) and
- (AComponent = ItemsDataSource) then ItemsDataSource := nil;
- end;
-
- end.
-